<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>手写promise</title>
</head>
<body>
<ol>
    <li>实现一个promise，在 setTimeout 中去 resolve</li>
    <li>实现一个promise，直接同步 resolve</li>
    <li>实现一个promise，防止 resolve 多次</li>
    <li>实现一个promise，可以让 then 方法链式调用</li>
    <li>实现一个promise，支持空 then 函数</li>
    <li>实现一个promise，支持 then 传递 thenable 对象</li>
    <li>实现一个promise，支持 then 传递 promise 对象</li>
    <li>实现一个promise，支持 resolve 传递 promise 对象</li>
</ol>
<script>
    const PENDING = "PENDING";
    const FULFILLED = "FULFILLED";
    const REJECTED = "REJECTED";

    const promiseResolutionProcedure = (x,resolve,reject) => {
        // 处理promise对象
        if(x instanceof MyPromise){
            if(x.state === PENDING){
                x.then(y => {
                    promiseResolutionProcedure(y,resolve,reject);
                },reject)
            } else {
                x.state === FULFILLED && resolve(x.value);
                x.state === REJECTED && reject(x.value);
            }
        }
        // 判断thenable对象
        if((typeof x === "object" || typeof x === "function") && x !== null){
            if(typeof x.then === "function"){
                x.then(y => {
                    promiseResolutionProcedure(y,resolve,reject);
                },reject);
            } else {
                resolve(x);
            }
        } else {
            resolve(x);
        }
    }

    class MyPromise{
        constructor(fn) {
            this.state = PENDING;
            this.value = undefined;
            this.resolveCallbacks = [];

            const resolve = val => {
                if(typeof val === "object" || typeof val === "function"){
                    promiseResolutionProcedure(val,resolve,reject);
                    return;
                }
                setTimeout(() => {
                    // 只有第一个resolve生效
                    if(this.state === PENDING){
                        this.state = FULFILLED;
                        this.value = val;
                        this.resolveCallbacks.map(fn => fn(val));
                    }
                })
            }

            const reject = val => {
                this.state = REJECTED;
                this.value = val;
            }

            fn(resolve,reject);
        }

        then(onFulfilled = val => val){
            if(this.state === PENDING){
                return new MyPromise((resolve,reject) => {
                    this.resolveCallbacks.push(() => {
                        const x = onFulfilled(this.value);
                        promiseResolutionProcedure(x,resolve,reject)
                    })
                })
            }
        }
    }



    new MyPromise((resolve,reject) => {
        resolve(new MyPromise((resolve,reject) => {
            resolve('step8');
        }))

    }).then(res => {
        console.log(res);
        return new MyPromise((resolve,reject) => {
            resolve('step8.2');
        })
    }).then()  // 空then
        .then(res => {
            console.log(res);
        });
</script>
</body>
</html>